/* 
 * File:   VertChImpl.h
 * Author: boyan
 *
 * Created on March 23, 2009, 1:07 AM
 */

#ifndef _VERTCHIMPL_H
#define	_VERTCHIMPL_H


#define PRINTSTUFF  0

//////////////////////////////////////
// this is the base abstract class

#include "AlignDomain.h"

#include <MeshInterface.hpp>

class VerticesChooser
{
public:
    static VerticesChooser *DEFAULT_CHOOSER_2D;
    static VerticesChooser *DEFAULT_CHOOSER_3D;

    virtual bool choose_nodes(Mesquite::Mesh *mesh, const AlignDomain *domain,
                              LevelsetCode_array &inside_codes) = 0;

    virtual bool support_dimension(int dim) const = 0;

    virtual ~VerticesChooser()
    {
    }
};

//////////////////////////////////////////////////////////////////////////////

#include "cxx_misc.h"
#include <iostream>
#include <vector>

#include <PatchData.hpp>

class PendingNode
{
public:
    size_t node; // index of the node in grid
    signed int code; // code is used by the choosing procedure.
    //           >0 means chosen to move; <=0 means not chosen to move
    size_t NCE; // number of crossed edges on node
    double_t dist; // distance to surface
    Mesquite::Vector3D proj; // position of the nearest point on the surface

    PendingNode(int n)
    : node(n), code(0), NCE(0), dist(0.0), proj(0.0, 0.0, 0.0)
    {
    }

    PendingNode(int n, double d, Mesquite::Vector3D p)
    : node(n), code(0), NCE(0), dist(d), proj(p)
    {
    }

    static bool compare_distance_inc(const PendingNode &left,
                                     const PendingNode &right)
    {
        return left.dist < right.dist;
    }

    static bool compare_connectivity_dec(const PendingNode &left,
                                         const PendingNode &right)
    {
        return left.NCE != right.NCE ? left.NCE > right.NCE
                : left.dist < right.dist;
    }
};

class VertCh_base : public VerticesChooser
{
    /////////////////////////////////////////////////////////////////////////
    // An abstract base class that provides all machinary
    // related to pending nodes and crossed edges
public:

    virtual bool choose_nodes(Mesquite::Mesh *msh,
                              const AlignDomain *dom,
                              LevelsetCode_array &levelset_codes);

    void dump_pending_nodes(std::ostream &S = std::cout);
    void dump_crossed_edges(std::ostream &S = std::cout);

protected:
    const AlignDomain *domain;
    LevelsetCode_array *levelset_codes;

    Mesquite::PatchData global_patch;


    // choose nodes basically does { init(); choose(); restore(); done(); }
    //  if you overload any virtual methods that are implemented here,
    //  make sure to call the base class method from within your implementation.
    virtual void init();
    virtual void done();
    virtual void restore();
    virtual bool choose() = 0; // pure virtual

    virtual bool try_restore(size_t node_index,
                             LevelsetCode &level);

    typedef fixed_size_vector_with_int_codes<size_t, 2 > CrossedEdge;
    std::vector<CrossedEdge> CE; // the crossed edges
    std::vector<PendingNode> PN; // indices of pending nodes
    std::vector<int> vert_NCE; // number of crossed edges per node

    friend bool operator<(const VertCh_base::CrossedEdge &L,
            const VertCh_base::CrossedEdge &R);

    //======================================================================
    // some utility functions ==============================================

    inline bool is_edge_crossed(size_t *nds)
    {
        const Mesquite::Mesh::VertexHandle *h;
        h = global_patch.get_vertex_handles_array();
        return (*levelset_codes)[h[nds[0]]]*(*levelset_codes)[h[nds[1]]] <= 0;
    }

    inline bool is_node_pending(size_t node) const
    {
        return vert_NCE[node] > 0;
    }

private:
    void init_crossed_edges();
    void init_pending_nodes();
};


#endif	/* _VERTCHIMPL_H */

